package com.tqz.rc.server.healthcheck;

import com.tqz.rc.api.BeatInfo;
import com.tqz.rc.api.Cluster;
import com.tqz.rc.api.Instance;
import com.tqz.rc.common.util.DateUtil;
import com.tqz.rc.server.core.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * <p>服务端对客户端心跳请求的处理类。
 * 客户端向服务端请求注册服务的接口的时候，同时也会请求一个心跳接口，
 * 客户端默认每5秒钟执行一次。
 *
 * @author tianqingzhao
 * @since 2021/8/31 14:38
 */
public class ClientBeatProcessor implements Runnable {

    private static final Logger log = LoggerFactory.getLogger(ClientBeatProcessor.class);

    private BeatInfo beatInfo;

    private Service service;

    public BeatInfo getBeatInfo() {
        return beatInfo;
    }

    public void setBeatInfo(BeatInfo beatInfo) {
        this.beatInfo = beatInfo;
    }

    public Service getService() {
        return service;
    }

    public void setService(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        String clusterName = beatInfo.getClusterName();
        String ip = beatInfo.getIp();
        int port = beatInfo.getPort();

        if (log.isDebugEnabled()) {
            log.debug("服务端接收客户端 [ clusterName：{}， ip：{}，port：{} ]请求的心跳检查的时间：{}", DateUtil.getCurDateTime(), clusterName, ip, port);
        }

        Cluster cluster = service.getClusterMap().get(clusterName);
        List<Instance> instances = cluster.allIps(true);

        for (Instance instance : instances) {
            if (instance.getIp().equals(ip) && instance.getPort() == port) {
                instance.setLastBeat(System.currentTimeMillis());

                // 如果该实例不健康就设置为健康状态，这种情况很难发生。
                // 因为即使某一个实例不健康的时候，再次注册会重新设置为健康状态，
                // 客户端请求注册的接口是立马执行，而该任务是每5秒钟执行一次，
                // 也就是在客户端请求注册的接口的5秒钟之后才会执行到该任务。
                if (!instance.isHealthy()) {
                    instance.setHealthy(true);

                    System.out.println("serviceName:" + service.getServiceName() + ",clusterName:" + clusterName +
                            ",ip:" + ip + ",port:" + port + "  client beat ok!");

                    // TODO 向订阅的服务发送服务变更的事件
                    service.getUdpPushService().serviceChanged(service);
                }
            }
        }

    }
}
